package com.qkun.library.utils;

import androidx.annotation.NonNull;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * @author qinkun
 * @date 6/24 0024 22:29
 * @description
 */
public final class ArraysEx {

    public static boolean isEmpty(Object[] array) {
        return Utils.isNull(array) || array.length == 0;
    }

    public static boolean isEmpty(int[] array) {
        return Utils.isNull(array) || array.length == 0;
    }

    public static boolean isEmpty(float[] array) {
        return Utils.isNull(array) || array.length == 0;
    }

    public static boolean isEmpty(double[] array) {
        return Utils.isNull(array) || array.length == 0;
    }

    public static boolean isEmpty(byte[] array) {
        return Utils.isNull(array) || array.length == 0;
    }

    public static boolean isEmpty(long[] array) {
        return Utils.isNull(array) || array.length == 0;
    }

    public static boolean isEmpty(boolean[] array) {
        return Utils.isNull(array) || array.length == 0;
    }

    public static boolean isIncludeIndex(int arrayLength, int index) {
        return (index > -1) && (index < arrayLength);
    }

    public static boolean isIncludeIndex(Object[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static boolean isIncludeIndex(int[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static boolean isIncludeIndex(long[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static boolean isIncludeIndex(byte[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static boolean isIncludeIndex(float[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static boolean isIncludeIndex(boolean[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static boolean isIncludeIndex(short[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static boolean isIncludeIndex(double[] array, int index) {
        return Utils.nonNull(array) && isIncludeIndex(array.length, index);
    }

    public static void rangeCheck(int length, int from, int to) {
        if (from > to) {
            throw new IllegalArgumentException("from(" + from + ") > to(" + to + ")");
        }
        if (from < 0) {
            throw new ArrayIndexOutOfBoundsException(from);
        }
        if (to > length) {
            throw new ArrayIndexOutOfBoundsException(to);
        }
    }

    public static <T extends Comparable<V>, V> int binarySearch(@NonNull T[] a, V value) {
        return binarySearch(a, 0, a.length, value);
    }

    private static <T extends Comparable<V>, V> int binarySearch(T[] a, int from, int to, V value) {
        rangeCheck(a.length, from, to);
        to--;
        while (from <= to) {
            int mid = (from + to) >>> 1;
            int cmp = a[mid].compareTo(value);
            if (cmp < 0)
                from = mid + 1;
            else if (cmp > 0)
                to = mid - 1;
            else
                return mid;
        }
        return -(from + 1);
    }

    /**
     * 使用前提：a数组要是相对于value有序排序的
     *
     * @param a
     * @param value
     * @param c
     * @param <T>
     * @param <V>
     * @return
     */
    public static <T, V> int binarySearch(@NonNull T[] a, V value, @NonNull Comparator<? super T, V> c) {
        return binarySearch(a, 0, a.length, value, c);
    }

    public static <T, V> int binarySearch(@NonNull T[] a, int from, int to, V value, @NonNull Comparator<? super T, V> c) {
        rangeCheck(a.length, from, to);
        to--;
        while (from <= to) {
            int mid = (from + to) >>> 1;
            int cmp = c.compare(a[mid], value);
            if (cmp < 0)
                from = mid + 1;
            else if (cmp > 0)
                to = mid - 1;
            else
                return mid;
        }
        return -(from + 1);
    }

    public static byte[] merge(byte[] array, byte value) {
        if (array == null) {
            array = new byte[]{value};
        } else {
            //如果key在数组中，则返回搜索值的索引，否则返回-1或者”-x“(x：插入点）（元素不存在时索引由1开始,存在时由0开始）
            int index = Arrays.binarySearch(array, value);
            if (ArraysEx.isIncludeIndex(array, index)) {
                array[index] = value;
            } else {
                index = -(index + 1);//得到要插入的位置
                final int L = array.length;
                byte[] newArray = new byte[L + 1];
                if (index == L) {
                    System.arraycopy(array, 0, newArray, 0, L);
                } else if (index < L) {
                    System.arraycopy(array, 0, newArray, 0, index);
                    System.arraycopy(array, index, newArray, index + 1, L - index);
                } else {
                    throw new IndexOutOfBoundsException("length=" + L + " index=" + index);
                }
                newArray[index] = value;
                array = newArray;
            }
        }
        return array;
    }

    public static short[] merge(short[] array, short value) {
        if (array == null) {
            array = new short[]{value};
        } else {
            //如果key在数组中，则返回搜索值的索引，否则返回-1或者”-x“(x：插入点）（元素不存在时索引由1开始,存在时由0开始）
            int index = Arrays.binarySearch(array, value);
            if (ArraysEx.isIncludeIndex(array, index)) {
                array[index] = value;
            } else {
                index = -(index + 1);//得到要插入的位置
                final int L = array.length;
                short[] newArray = new short[L + 1];
                if (index == L) {
                    System.arraycopy(array, 0, newArray, 0, L);
                } else if (index < L) {
                    System.arraycopy(array, 0, newArray, 0, index);
                    System.arraycopy(array, index, newArray, index + 1, L - index);
                } else {
                    throw new IndexOutOfBoundsException("length=" + L + " index=" + index);
                }
                newArray[index] = value;
                array = newArray;
            }
        }
        return array;
    }

    public static double[] merge(double[] array, double value) {
        if (array == null) {
            array = new double[]{value};
        } else {
            //如果key在数组中，则返回搜索值的索引，否则返回-1或者”-x“(x：插入点）（元素不存在时索引由1开始,存在时由0开始）
            int index = Arrays.binarySearch(array, value);
            if (ArraysEx.isIncludeIndex(array, index)) {
                array[index] = value;
            } else {
                index = -(index + 1);//得到要插入的位置
                final int L = array.length;
                double[] newArray = new double[L + 1];
                if (index == L) {
                    System.arraycopy(array, 0, newArray, 0, L);
                } else if (index < L) {
                    System.arraycopy(array, 0, newArray, 0, index);
                    System.arraycopy(array, index, newArray, index + 1, L - index);
                } else {
                    throw new IndexOutOfBoundsException("length=" + L + " index=" + index);
                }
                newArray[index] = value;
                array = newArray;
            }
        }
        return array;
    }

    public static long[] merge(long[] array, long value) {
        if (array == null) {
            array = new long[]{value};
        } else {
            //如果key在数组中，则返回搜索值的索引，否则返回-1或者”-x“(x：插入点）（元素不存在时索引由1开始,存在时由0开始）
            int index = Arrays.binarySearch(array, value);
            if (ArraysEx.isIncludeIndex(array, index)) {
                array[index] = value;
            } else {
                index = -(index + 1);//得到要插入的位置
                final int L = array.length;
                long[] newArray = new long[L + 1];
                if (index == L) {
                    System.arraycopy(array, 0, newArray, 0, L);
                } else if (index < L) {
                    System.arraycopy(array, 0, newArray, 0, index);
                    System.arraycopy(array, index, newArray, index + 1, L - index);
                } else {
                    throw new IndexOutOfBoundsException("length=" + L + " index=" + index);
                }
                newArray[index] = value;
                array = newArray;
            }
        }
        return array;
    }

    public static float[] merge(float[] array, float value) {
        if (array == null) {
            array = new float[]{value};
        } else {
            //如果key在数组中，则返回搜索值的索引，否则返回-1或者”-x“(x：插入点）（元素不存在时索引由1开始,存在时由0开始）
            int index = Arrays.binarySearch(array, value);
            if (ArraysEx.isIncludeIndex(array, index)) {
                array[index] = value;
            } else {
                index = -(index + 1);//得到要插入的位置
                final int L = array.length;
                float[] newArray = new float[L + 1];
                if (index == L) {
                    System.arraycopy(array, 0, newArray, 0, L);
                } else if (index < L) {
                    System.arraycopy(array, 0, newArray, 0, index);
                    System.arraycopy(array, index, newArray, index + 1, L - index);
                } else {
                    throw new IndexOutOfBoundsException("length=" + L + " index=" + index);
                }
                newArray[index] = value;
                array = newArray;
            }
        }
        return array;
    }

    public static int[] merge(int[] array, int value) {
        if (array == null) {
            array = new int[]{value};
        } else {
            //如果key在数组中，则返回搜索值的索引，否则返回-1或者”-x“(x：插入点）（元素不存在时索引由1开始,存在时由0开始）
            int index = Arrays.binarySearch(array, value);
            if (ArraysEx.isIncludeIndex(array, index)) {
                array[index] = value;
            } else {
                index = -(index + 1);//得到要插入的位置
                final int L = array.length;
                int[] newArray = new int[L + 1];
                if (index == L) {
                    System.arraycopy(array, 0, newArray, 0, L);
                } else if (index < L) {
                    System.arraycopy(array, 0, newArray, 0, index);
                    System.arraycopy(array, index, newArray, index + 1, L - index);
                } else {
                    throw new IndexOutOfBoundsException("length=" + L + " index=" + index);
                }
                newArray[index] = value;
                array = newArray;
            }
        }
        return array;
    }

    public static <V extends Comparable<T>, T> V[] merge(V[] array, @NonNull V value, @NonNull T sortBy) {
        if (array == null) {
            array = (V[]) Array.newInstance(value.getClass(), 1);
            array[0] = value;
        } else {
            //如果key在数组中，则返回搜索值的索引，否则返回-1或者”-x“(x：插入点）（元素不存在时索引由1开始,存在时由0开始）
            int index = binarySearch(array, sortBy);
            if (ArraysEx.isIncludeIndex(array, index)) {
                array[index] = value;
            } else {
                index = -(index + 1);//得到要插入的位置
                final int L = array.length;
                V[] newArray = (V[]) Array.newInstance(value.getClass(), L + 1);
                if (index == L) {
                    System.arraycopy(array, 0, newArray, 0, L);
                } else if (index < L) {
                    System.arraycopy(array, 0, newArray, 0, index);
                    System.arraycopy(array, index, newArray, index + 1, L - index);
                } else {
                    throw new IndexOutOfBoundsException("length=" + L + " index=" + index);
                }
                newArray[index] = value;
                array = newArray;
            }
        }
        return array;
    }

    public static <V extends Comparable<V>> V[] merge(V[] array, @NonNull V value) {
        return merge(array, value, value);
    }

    public interface Comparator<T, V> {
        int compare(T o, V value);
    }
}
